﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Speakup;
using System.Threading;
using WebLayer;
using WebPageParser;

namespace Frontend
{
    enum RefresherState { Completed, Cancelled, ErrorOccured, InPorgress, NotStarted }

    class RefresherStateEventArgs: EventArgs
    {
        public RefresherState OldStatus;
        public RefresherState NewStatus;
        public Refresher Refresher;
    }

    class Refresher
    {
        private ClassList m_classList = new ClassList();
        public ClassList ClassList
        {
            get
            {
                return m_classList;
            }
            private set
            {
                m_classList = value;
            }
        }

        private PersonalStats m_personalStats = new PersonalStats();
        public PersonalStats PersonalStats
        {
            get
            {
                return m_personalStats;
            }
            private set
            {
                m_personalStats = value;
            }
        }
        
        RefresherState m_state = RefresherState.NotStarted;
        public RefresherState State
        {
            get
            {
                return m_state;
            }
            private set
            {
                RefresherState oldState = m_state;
                m_state = value;

                OnStateChanged(oldState);
            }
        }

        public String ErrorMessage { get; private set; }

        //for refreshing classes in separate thread
        private LoginToken Token;
        private Thread Thread;
        private SynchronizationContext context;
        
        //state changes events
        public event EventHandler<RefresherStateEventArgs> StateChanged;

        public Refresher()
        {
            context = SynchronizationContext.Current;
            if (context == null)
            {
                context = new SynchronizationContext();
            }

            ErrorMessage = "Everything is fine.";
        }

        protected void OnStateChanged(RefresherState oldStatus)
        {
            RefresherStateEventArgs args = new RefresherStateEventArgs();
            args.NewStatus = State;
            args.OldStatus = oldStatus;
            args.Refresher = this;
            SendStateChanged(this, args);            
        }

        private void SendStateChanged(object sender, RefresherStateEventArgs args)
        {
            foreach (Delegate d in StateChanged.GetInvocationList())
            {
                SendOrPostCallback callback = new SendOrPostCallback(delegate(object state)
                {
                    object[] rawArg = { sender, args };
                    d.DynamicInvoke(rawArg);
                });

                context.Post(callback, null);
            }
        }

        public void StartRefresh(string user, string password, string school, ClassList classList)
        {
            ClassList.Clear();
            ClassList.Merge(classList);
            Token = new LoginToken(user, password, school);

            Thread = new Thread(RefresherThread);
            Thread.Start();          
        }

        public void CancelRefresh()
        {
            if (Thread != null)
            {
                Thread.Abort();               
            }
        }

        void RefresherThread()
        {
            ErrorMessage = "Unknown error occured!";
            State = RefresherState.InPorgress;

            try
            {
                WebPageCache cache = new WebPageCache();
                cache.LoginToken = Token;

                ClassList.Refresh(Speakup.ClassList.RefreshType.FutureClasses, cache);
                PersonalStats = PersonalStats.Fetch(cache);

                //ClassListThemeAssigner.AssignThemes(ClassList, PersonalStats.Level);
                AttendencyAssigner.AssignAttendedToClasses(ClassList, PersonalStats);

                State = RefresherState.Completed;
                ErrorMessage = "Refresh completed without problems!";
            }
            catch (UnauthorizedAccessException)
            {
                State = RefresherState.ErrorOccured;
                ErrorMessage = "You provided invalid user/password/school values. Please correct them and retry.";
            }
            catch (ThreadAbortException)
            {
                State = RefresherState.Cancelled;
                
            }
            catch (Exception ex)
            {
                State = RefresherState.ErrorOccured;
                ErrorMessage = ex.Message;

                if(ex.InnerException != null)
                {
                    int index = 1;

                    ErrorMessage = index.ToString() + ") " + ErrorMessage+"\n";

                    while (ex.InnerException != null)
                    {
                        index++;
                        ex = ex.InnerException;
                        ErrorMessage+= (index - 1).ToString()+" caused by " +index.ToString()+") "+ex.Message +"\n";
                    }                                       
                }

            }            
        }
        
    }
}
